docker系列之使用docker-compose部署Nginx+MySQL+MongoDB+Spring Boot项目

这篇文章讲一讲将项目容器化的实践,主要内容包括以下几个方面:

  1. docker-compose部署spring boot项目
  2. docker MongoDB的加密配置
  3. 谈一谈docker的使用、项目的部署等

docker-compose部署项目

如果一个项目有很多依赖的环境,如各类数据库,同时又想使用docker这项虚拟化服务的技术,那么就可以尝试使用docker完成一次性部署。本文主要结合上次一个spring boot 开发web的项目的实际经历来记录一下使用docker-compose部署项目的一些经验。
找到了一本docker的中文文档,其将docker定义为:

Compose 定位是 「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)」,负责实现对 Docker 容器集群的快速编排。其前身是开源项目 Fig。

也就是说利用docker-compose可以快速打包多个docker应用,我们的项目中需要用到 Nginx+MySQL+MongoDB+spring boot项目,所以docker-compose也就是对这些容易进行打包,首先来看一下一个docker-compose.yaml的模板文件内容吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
version: '3'
services:
nginx:
container_name: v-nginx
image: nginx
restart: always
ports:
- 80:80
- 443:443
volumes:
- ~/spring-website-docker/nginx/conf.d:/etc/nginx/conf.d
- ~/nginx-log:/var/log/nginx
- /etc/localtime:/etc/localtime

mysql:
container_name: mymysql
image: mysql
environment:
MYSQL_DATABASE: java_web
MYSQL_ROOT_PASSWORD: ******
MYSQL_ROOT_HOST: '%'
ports:
- "27018:3306"
volumes:
- ~/spring-website-docker/mysql-entrypoint:/docker-entrypoint-initdb.d
- ~/create_user_table.sql:/create_user_table.sql
- /etc/localtime:/etc/localtime
restart: always

mongo:
container_name: mongo
image: mongo
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=*******
volumes:
- ~/mongodb:/data/db
- ~/mongo-log:/data/log
- ~/spring-website-docker/mongo-entrypoint:/docker-entrypoint-initdb.d
- /etc/localtime:/etc/localtime
ports:
- "27018:27017"
restart: always
command: mongod

spring-blog-website:
restart: always
build: ./spring-blog-website
working_dir: /spring-blog-website
volumes:
- ./spring-blog-website:/spring-blog-website
- ~/.m2:/root/.m2
- ~/upload-dir:/spring-blog-website/upload-dir
- /etc/localtime:/etc/localtime
expose:
- "8080"
depends_on:
- nginx
- mysql
- mongo
command: mvn clean spring-boot:run -Dspring-boot.run.profiles=docker

简单分析一下上面的文件内容,有两组内容,分别是version和services,services下面包含着所有要打包的应用的名称,也是容易的名称,如果容器是从官网上pull下来的,那么容器名就是pull下来的容器名。
像container_name 是自己定义的。有几组映射关系,像ports的映射、volumes的映射,简单将映射简化为<A:B>,A为主机的资源,B为容器内的资源。

1
2
ports:
- "27018:3306"

这组映射的意思就是把主机的27018端口映射到mymysql容器的3306端口下。
而volumes的映射是将磁盘的内容同步映射。有了上面的基本了解,还有一个是command指令,意思是在容器开启之后,自动执行的命令。

关于docker-compose的部署在文档中写的也很清楚,可以参见docker compose。重点看一下命令说明那块的内容,里面讲的很详细

下面再说一下docker-compose中如何组织加密MongoDB的部署

dockercompose中 MongoDB的加密配置

如果没有docker-compose,我们想要配置一个加密的MongoDB数据库,可以先不加密开启,然后添加一个admin数据库用户,然后再通过admin这个账户创建其他一般数据库的账户。如我在本地开启一个加密的MongoDB的数据库,只需要下面几步内容:

  1. 在admin数据库中设置了管理员账户,用来管理其他库
    db.createUser({ user: “blogweb”, pwd: “password”, roles: [{ role: “userAdminAnyDatabase”, db: “admin” }] i})

  2. 然后在MongoDB的配置文件中开启安全选项,这一步不做也可以,直接重启MongoDB数据,在重启命令后面加上–auth,然后再添加其他数据库的账号信息

  3. 添加其他数据库的加密账户,如abcd数据库的账户:
    db.createUser({ user: “qwerty”, pwd: “password123.”, roles: [{ role: “dbOwner”, db:”abcd” }] })
    然后就可以使用这个账号登录该数据库了,这个时候设置了admin的账户,即使知道了admin的账户,也进不去java_web的账户,从而提高数据库的安全性。

参考资料:https://juejin.im/post/5b0519cf518825426539d05e

但是在docker-compose中,我们是利用docker开启mongo服务的,没有–auth这种命令选项,那么该如何做呢?请看service代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mongo:
container_name: mongo
image: mongo
environment:
- MONGO_INITDB_ROOT_USERNAME=root
- MONGO_INITDB_ROOT_PASSWORD=*******
volumes:
- ~/mongodb:/data/db
- ~/mongo-log:/data/log
- ~/spring-website-docker/mongo-entrypoint:/docker-entrypoint-initdb.d
- /etc/localtime:/etc/localtime
ports:
- "27018:27017"
restart: always
command: mongod

即在mongo的environment中添加一个root账户,就不需要手动开启–auth选项了。等待容器开启之后,在command中自动执行脚本mongo.sh,或者手动执行也可以。

1
2
3
4
5
6
7
8
9
#mongo.sh
#!/usr/bin/env bash
echo "Creating mongo users..."
mongo admin --host localhost -u root -p ******* --eval "db.createUser({user: 'admin', pwd: 'password', roles: [{role: 'userAdminAnyDatabase', db: 'admin'}]});"
mongo admin -u root -p ******* << EOF
use abcd
db.createUser({user: 'qwerty', pwd: 'password123', roles:[{role:'readWrite',db:'abcd'}]})
EOF
echo "Mongo users created."

手动执行脚本的时候,docker命令为:sudo docker exec -it 容器名或者是容器ID /bin/bash
在上述执行的时候,可能会出现message: ‘Authentication failed.’, mongo-express_1 | ok: 0,,类似的问题,这个时候不要怀疑是你的root账户没有生效,是因为你的volume中,有以前未加密的数据库文件,就导致了这个错误。这个时候只需要使用rm -r清空你的mongodb数据库的存储文件即可,或者docker-compose启动时加上下面的参数

1
docker-compose up --force-recreate --renew-anon-volumes

参考资料

谈一谈docker的使用、项目的部署等

在之前的一篇文章中,我提到了能不能把整个项目打包成一个容器,在后续的测试、版本更新的过程中,我有了一些新的体会。
比如在该项目中,MongoDB和MySQL数据库容器都已经配置完毕,里面已经存有一些数据,但是我要是想更新我的项目代码,在之前的那种想法中,数据库会重新初始化,里面的数据也就不在了,这在实际的生产中明显是不可行的。现在的这种方式,利用docker-compose部署完项目后,假如我的spring boot项目的代码进行了修改,要重新部署,只需要将对应的代码传到服务器中项目的位置,其他的配置都不需要改变,还是相当方便的,还不知道公司里面发布代码是怎么个流程,如果有小伙伴在公司上班,还请告知一二。

那是不是第一种想法在现实中就没有应用呢?当然不是,wiznote就是个案例,wiznote在官网上提供了一个2g左右大小的docker容器,只需要一键即可将其部署到自己的服务器上,实现自己的服务,还是相当不错的,只不过是占用的内存稍多了些。这个容器就是将所有的组件打包到一个容器中,实现一键部署。如果你的代码很稳定,不需要改变,那么可以使用这种方式。

Screen Shot 2019-12-26 at 09.34.50